import common,urllib,httplib,socket,Queue,threading,thread
import ConnectionService
import requests
import re,thread,time
import unittest

globalVars = common.getGlobalVars()

rePhraseResponse = re.compile(\
        r"HTTP/\d.\d *(\d+) *(.+)\r\n((?:.*\r\n)*?)\r\n")
rePhraseHeader = re.compile(\
        r"(?:([^:]+): *(.*)\r\n)")
class FetchCore:
    proxy = None
    fetch_server = None
    
        
    def __init__(self):
        self.count = 0
        self.fetch_server = common.globalVars.FETCH_SERVER 
        self.CM = ConnectionService.getCM()
        self.CM.getSessionSimple(block = True)#wait for first good proxy
        
    def doFetch(self,params):
        session = self.CM.getSessionSimple(block = True)
        common.logger(3,"FetchCore.doFetch", "count %d" %(self.count,))
        try:
            resp = session.session.post(self.fetch_server,
                                data=params,
                                verify= True,timeout=20
                                  )
            return Response(resp)
        except requests.exceptions.ConnectionError or requests.exceptions.TimeOut ,e:

            common.logger(1,"FetchCore.doFetch.ConnectionError",e)
            self.CM.abandonSession(session)
            
            raise FetchCoreConnectionError(str(e))
        
        except FetchCoreEmptyResponse,e:
            common.logger(1,"FetchCore.doFetch.EmptyResponse",e)
            
            self.CM.abandonSession(session)
            raise
        
        except requests.exceptions.HTTPError,e:
            raise FetchCoreHttpError(e.code)
        
    def fetch(self, params,retry = 0):
        retry += 1
        for count in range(retry):
            try:
                resp = self.doFetch(params)
                return resp
            except Exception,e:
                common.logger(1,"FetchCore.fetch.Exception","%s, retry %d" %(e,count))
                if retry - count == 1:
                    raise
                else:
                    continue

    
    def shutdown(self):
        self.CM.shutDown()

class FetchCoreError(Exception):
    def __init__(self, reason):
        self.reason = reason

    def __str__(self):
        return '<FetchCoreError Error: %s>' % self.reason
    
class FetchCoreConnectionError(FetchCoreError):
    def __str__(self):
        return '<FetchCoreConnectionError Error: %s>' % self.reason

class FetchCoreHttpError(FetchCoreError):
    def __init__(self, reason,code):
        self.reason = reason
        self.code = code
        
class FetchCoreEmptyResponse(FetchCoreError):
    def __str__(self):
        return '<FetchCoreEmptyResponse Error: %s>' % self.reason


class Response:
    def __init__(self,response):
        self.headers = {}
        self.setcookie = []
        self.phraser(response.content)
        
    def phraser(self,responseContent):
        matchGroup = rePhraseResponse.match(responseContent)
        if matchGroup == None:
            raise FetchCoreEmptyResponse("Empty Content")
        self.status = int(matchGroup.group(1))
        self.reason = matchGroup.group(2)
        headerLines = matchGroup.group(3)
        headerGroup = rePhraseHeader.findall(headerLines)
        for headerKey, headerValue in headerGroup:
            headerKey = headerKey.lower().strip()
            headerValue = headerValue.strip()
            if headerKey == "set-cookie":
                self.setcookie.append(headerValue)
            else:
                self.headers[headerKey] = headerValue
        wordPos = responseContent.find("\r\n\r\n")
        self.payload = responseContent[wordPos+4::]
     
class fetchcoreUnitTest(unittest.TestCase):
    def test_Response_emptyRespond(self):
        self.assertRaises(FetchCoreError,Response,FakeClasses.FakeResponse())

    def test_Response_normalRespond(self):
        r = FakeClasses.FakeResponse()
        r.setNormal()
        newResponse = Response(r)
        self.assertTrue(r.checkResponse(newResponse))

    def test_FetchCore_InitSession(self):
        for count in [1,2,10]:
            FCM = FakeClasses.FakeConnectionManager(count)
            self.assertEqual(len(FCM.newSessions),count)
            ConnectionService.getCM = FCM.getCM
            fetchcore = FetchCore()
            self.assertEqual(len(fetchcore.sessions),count)
            fetchcore.shutdown()
            
    def test_FetchCore_Normal(self):
        FCM = FakeClasses.FakeConnectionManager(1)
        ConnectionService.getCM = FCM.getCM
        fetchcore = FetchCore()
        resp = fetchcore.doFetch("testdata")
        r = FakeClasses.FakeResponse()
        r.setNormal()
        self.assertTrue(r.checkResponse(resp))
        fetchcore.shutdown()
        
    def test_FetchCore_EmptyResponse(self):
        FCM = FakeClasses.FakeConnectionManager(1)
        ConnectionService.getCM = FCM.getCM
        fetchcore = FetchCore()
        self.assertRaises(FetchCoreEmptyResponse,fetchcore.doFetch,\
                          "EmptyResponse")
        
        fetchcore.shutdown()

    def test_FetchCore_ConnectionError(self):
        FCM = FakeClasses.FakeConnectionManager(2)
        ConnectionService.getCM = FCM.getCM
        fetchcore = FetchCore()
        self.assertRaises(FetchCoreConnectionError,fetchcore.doFetch,\
                          "ConnectionError")      
        fetchcore.shutdown()
        
        
        

if __name__ == "__main__":
    from unit_test import FakeClasses
    unittest.main()


        

